package com.ruoyi.wechat.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.wechat.domain.WxMpAuthorizationUrl;
import com.ruoyi.wechat.service.IWeChatBaseService;
import com.ruoyi.weixin.domain.LoginMaDTO;
import me.chanjar.weixin.mp.api.WxMpService;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.UUID;


/**
 * @author cj
 */
@Service
public class WeChatBaseServiceImpl implements IWeChatBaseService {

//    @Autowired
//    WechatConfig wechatConfig;

    @Autowired
    private WxMpService wxMpService;

    String accessTokenKey = UUID.randomUUID().toString();


    /**
     * 1. 获取全局access_token的接口地址（GET） 限200（次/天）
     */
    public static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET";

    /**
     * 2. 用于进行网页授权验证的接口URL，通过这个才可以得到opendID等字段信息
     */
    public static final String GET_WEB_AUTH_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";

    /**
     * 3. 获取用户详情
     */
    public static final String GET_USERINFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";


    @Override
    public R<String> getAccessToken() {
        String result = storeAccessToken();
        if (StringUtils.isEmpty(result)) {
            return R.ok("获取 access token 成功",result);
        } else {
            return R.fail("获取 access token 失败");
        }
    }


    private String storeAccessToken() {
//        String requestUrl = GET_ACCESS_TOKEN_URL.replace("APPID", wechatConfig.getAppId())
//                .replace("SECRET", wechatConfig.getSecret());
        String requestUrl = GET_ACCESS_TOKEN_URL.replace("APPID", wxMpService.getWxMpConfigStorage().getAppId())
                .replace("SECRET", wxMpService.getWxMpConfigStorage().getSecret());
        String response = HttpUtils.sendGet(requestUrl, null);
        JSONObject jsonObject = JSONObject.parseObject(response);
        String sucessKey = "access_token";
        if (jsonObject.containsKey(sucessKey)) {
            Integer expiresIn = (Integer) jsonObject.get("expires_in");
            RedisUtils.setCacheObject(accessTokenKey, jsonObject.get("access_token"), Duration.ofSeconds(expiresIn));
            return jsonObject.get("access_token").toString();
        } else {
            return null;
        }
    }

    @Override
    public R<JSONObject> getUserInfo(String openId) {
        String accessToken = RedisUtils.getCacheObject(accessTokenKey);
        if (StringUtils.isEmpty(accessToken)) {
            accessToken = storeAccessToken();
        }
        assert accessToken != null;
        String requestUrl = GET_USERINFO_URL.replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String response = HttpUtils.sendGet(requestUrl, null);
        JSONObject jsonObject = JSONObject.parseObject(response);
        String sucessKey = "errcode";
        if (jsonObject.containsKey(sucessKey)) {
            String newAccessToken = storeAccessToken();
            requestUrl = GET_USERINFO_URL.replace("ACCESS_TOKEN", newAccessToken)
                    .replace("OPENID", openId);
            response = HttpUtils.sendGet(requestUrl, null);
            jsonObject = JSONObject.parseObject(response);
        }
        return R.ok("succ",jsonObject);
    }

    @Override
    public LoginMaDTO webAuth(String code) {
        R<JSONObject> resultR = getOpenIdByCode(code);
        JSONObject result =resultR.getData();
        if (result != null) {
            LoginMaDTO responseJson = new LoginMaDTO();
            responseJson.setOpenid(Convert.toStr(result.get("openid")));
            responseJson.setSessionKey(Convert.toStr(result.get("scope")));
            responseJson.setUnionid(Convert.toStr(result.get("unionid")));
            return responseJson;
        } else {
            return null;
        }
    }

    @Override
    public R<JSONObject> getOpenIdByCode(String code) {
        String requestUrl = GET_WEB_AUTH_URL.replace("APPID", wxMpService.getWxMpConfigStorage().getAppId())
                .replace("SECRET", wxMpService.getWxMpConfigStorage().getSecret())
                .replace("CODE", code);
        String response = HttpUtils.sendGet(requestUrl, null);
        JSONObject jsonObject = JSONObject.parseObject(response);
        String sucessKey = "access_token";
        if (jsonObject.containsKey(sucessKey)) {
            return R.ok("succ",jsonObject);
        } else {
            return R.fail("获取失败");
        }
    }



    @Override
    public String webLogin(String code) {
        R<JSONObject> resultR = getOpenIdByCode(code);
        JSONObject result=resultR.getData();
        String sucessKey = "openid";
        if (result != null && result.containsKey(sucessKey)) {
            return result.get("openid").toString();
        } else {
            return null;
        }
    }

    @Override
    public String getWebAuthUrl(WxMpAuthorizationUrl wxMpAuthorizationUrl) {
        String response = wxMpService.getOAuth2Service().buildAuthorizationUrl(wxMpAuthorizationUrl.getRedirectUrl(), wxMpAuthorizationUrl.getScope(), wxMpAuthorizationUrl.getState());
        //System.out.println(response);
        return response;
    }

    @Override
    public String getSignature(String url) {
        String signature = "";
        //获取noncestr
        String noncestr = UUID.randomUUID().toString();
        //获取timestamp
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        //获取access_token
        String access_token = storeAccessToken();
        //获取jspai_ticket
        String jsapi_ticket = getTicket(access_token);
        //将四个数据进行组合，传给SHA1进行加密
        String str = "jsapi_ticket=" + jsapi_ticket +
            "&noncestr=" + noncestr +
            "&timestamp=" + timestamp +
            "&url=" + url;
        //sha1加密
        signature = SHA1(str);
        return signature ;
    }

    public String getTicket(String accessToken) {
        // 网页授权接口
        String GetPageAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi";
        HttpClient client = null;
        String ticket = "";
        int expires_in = 0;
        try {
            client = new DefaultHttpClient();
            HttpGet httpget = new HttpGet(GetPageAccessTokenUrl);
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            String response = client.execute(httpget, responseHandler);
            JSONObject OpenidJSONO = JSONObject.parseObject(response);
            ticket = String.valueOf(OpenidJSONO.get("ticket"));//获取ticket
            expires_in = Integer.parseInt(String.valueOf(OpenidJSONO.get("expires_in")));//获取时间
        } catch (Exception e) {
//            throw new CommonRuntimeException("获取Ticket出错！");
        } finally {
            client.getConnectionManager().shutdown();
        }

        return ticket;
    }

    public String SHA1(String str) {
        try {
            MessageDigest digest = MessageDigest
                .getInstance("SHA-1"); //如果是SHA加密只需要将"SHA-1"改成"SHA"即可
            digest.update(str.getBytes());
            byte messageDigest[] = digest.digest();
            // Create Hex String
            StringBuffer hexStr = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }
            return hexStr.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
}
